/*
* This file is part of QSerialDevice, an open-source cross-platform library
* Copyright (C) 2009  Denis Shienkov
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* Contact Denis Shienkov:
*          e-mail: <scapig2@yandex.ru>
*             ICQ: 321789831
*/

#ifndef NATIVESERIALENGINE_H
#define NATIVESERIALENGINE_H

#include <QtCore/QStringList>

#include "abstractserialengine.h"

class NativeSerialEnginePrivate;
class NativeSerialEngine : public AbstractSerialEngine
{
    Q_OBJECT
public:
    explicit NativeSerialEngine(QObject *parent = 0);
    virtual ~NativeSerialEngine();

    bool open(AbstractSerial::OpenMode mode);
    void close();

    bool setBaudRate(AbstractSerial::BaudRate baudRate);
    bool setInputBaudRate(AbstractSerial::BaudRate baudRate);
    bool setOutputBaudRate(AbstractSerial::BaudRate baudRate);
    bool setDataBits(AbstractSerial::DataBits dataBits);
    bool setParity(AbstractSerial::Parity parity);
    bool setStopBits(AbstractSerial::StopBits stopBits);
    bool setFlowControl(AbstractSerial::Flow flow);
    bool setCharIntervalTimeout(int msecs);

    bool setDtr(bool set) const;
    bool setRts(bool set) const;
    quint16 lineStatus() const;

    bool sendBreak(int duration) const;
    bool setBreak(bool set) const;

    bool flush() const;
    bool reset() const;

    qint64 bytesAvailable() const;

    qint64 read(char *data, qint64 maxSize);
    qint64 write(const char *data, qint64 maxSize);

    bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
                            bool checkRead, bool checkWrite,
                            int msecs = 3000);

    bool isReadNotificationEnabled() const;
    void setReadNotificationEnabled(bool enable);

protected:

    //add 05.11.2009
    enum ioQueue{ txQueue, rxQueue };
    qint64 currentTxQueue() const;
    qint64 currentRxQueue() const;

private:
    Q_DECLARE_PRIVATE(NativeSerialEngine)
    Q_DISABLE_COPY(NativeSerialEngine)
};

#ifdef Q_OS_WIN
#include <qt_windows.h>
#else
#include <termios.h>
#include "ttylocker.h"
#endif

class NativeSerialEnginePrivate : public AbstractSerialEnginePrivate
{
public:

    NativeSerialEnginePrivate();

    bool nativeOpen(AbstractSerial::OpenMode mode);
    bool nativeClose();

    bool nativeSetBaudRate(AbstractSerial::BaudRate baudRate);
    bool nativeSetInputBaudRate(AbstractSerial::BaudRate baudRate);
    bool nativeSetOutputBaudRate(AbstractSerial::BaudRate baudRate);
    bool nativeSetDataBits(AbstractSerial::DataBits dataBits);
    bool nativeSetParity(AbstractSerial::Parity parity);
    bool nativeSetStopBits(AbstractSerial::StopBits stopBits);
    bool nativeSetFlowControl(AbstractSerial::Flow flow);
    bool nativeSetCharIntervalTimeout(int msecs);

    bool nativeSetDtr(bool set) const;
    bool nativeSetRts(bool set) const;
    quint16 nativeLineStatus() const;

    bool nativeSendBreak(int duration) const;
    bool nativeSetBreak(bool set) const;

    bool nativeFlush() const;
    bool nativeReset() const;

    qint64 nativeBytesAvailable() const;

    qint64 nativeRead(char *data, qint64 len);
    qint64 nativeWrite(const char *data, qint64 len);

    int nativeSelect(int timeout, bool checkRead, bool checkWrite,
                bool *selectForRead, bool *selectForWrite);

    //add 05.11.2009  (while is not used, reserved)
    qint64 nativeCurrentQueue(NativeSerialEngine::ioQueue queue) const;

    inline bool isValid() const;

private:

#ifdef Q_OS_WIN
    COMMCONFIG cc, oldcc;
    COMMTIMEOUTS ct, oldct;

    OVERLAPPED oRx;
    OVERLAPPED oTx;
    OVERLAPPED oSelect;

    HANDLE hEvRx;
    HANDLE hEvTx;
    HANDLE hEvSelect;

    bool createEvents(bool evRx, bool evTx);
    bool closeEvents() const;
#else
    struct termios tio;
    struct termios oldtio;
    TTYLocker locker;
#endif

    bool detectDefaultBaudRate();
    bool detectDefaultDataBits();
    bool detectDefaultParity();
    bool detectDefaultStopBits();
    bool detectDefaultFlowControl();

    bool detectDefaultCurrentSettings();

    bool setDefaultAsyncCharTimeout();

    void prepareOtherOptions();

    bool saveOldSettings();
    bool restoreOldSettings();
};

#endif // NATIVESERIALENGINE_H
